#include "rtp/RtpPacket.h"
#include <iostream>
#include <cassert>


namespace Rtp {
    RtpPacket* RtpPacket::Parse(const uint8_t* data, size_t len) {
        // Implement the parsing logic here.
        // This is a placeholder implementation.
        if (!IsRtp(data, len)) {
            return nullptr; // Not a valid RTP packet.
        }

        auto* ptr = const_cast<uint8_t*>(data);
        auto* header = reinterpret_cast<Header*>(ptr);

        ptr += HeaderSize;

        // Check CSRC list.
		size_t csrcListSize{ 0u };

        if (header->csrcCount != 0u)
		{
			csrcListSize = header->csrcCount * sizeof(header->ssrc);

			// Packet size must be >= header size + CSRC list.
			if (len < (ptr - data) + csrcListSize) {
                std::cout << "RtpPacket::Parse() | not enough space for the CSRC list, packet discarded" << std::endl;
				return nullptr;
			}
			ptr += csrcListSize;
		}

        // Check header extension.
		HeaderExtension* headerExtension{ nullptr };
		size_t extensionValueSize{ 0u };
        if (header->extension == 1u) {
			// The header extension is at least 4 bytes.
			if (len < static_cast<size_t>(ptr - data) + 4) {
                std::cout << "RtpPacket::Parse() | not enough space for the header extension, packet discarded" << std::endl;
				return nullptr;
			}

			headerExtension = reinterpret_cast<HeaderExtension*>(ptr);

			// The header extension contains a 16-bit length field that counts the number of
			// 32-bit words in the extension, excluding the four-octet header extension.
			extensionValueSize = static_cast<size_t>(ntohs(headerExtension->length) * 4);

			// Packet size must be >= header size + CSRC list + header extension size.
			if (len < (ptr - data) + 4 + extensionValueSize) {
                std::cout << "RtpPacket::Parse() | not enough space for the header extension value, packet discarded" << std::endl;
				return nullptr;
			}
			ptr += 4 + extensionValueSize;
		}

        // Get payload.
		uint8_t* payload     = ptr;
		size_t payloadLength = len - (ptr - data);
		uint8_t payloadPadding{ 0 };

		assert(len >= static_cast<size_t>(ptr - data));
		
        // Check padding field.
		if (header->padding != 0u)
		{
			// Must be at least a single payload byte.
			if (payloadLength == 0)
			{
				std::cout << "RtpPacket::Parse() | padding bit is set but no payload, packet discarded" << std::endl;
				return nullptr;
			}

			payloadPadding = data[len - 1];

			if (payloadPadding == 0)
			{
				std::cout << "RtpPacket::Parse() | padding byte cannot be 0, packet discarded" << std::endl;
				return nullptr;
			}

			if (payloadLength < size_t{ payloadPadding })
			{
				std::cout << "RtpPacket::Parse() | padding byte is greater than payload length, packet discarded" << std::endl;
				return nullptr;
			}

			payloadLength -= size_t{ payloadPadding };
		}

		assert(len == HeaderSize + csrcListSize + (headerExtension ? 4 + extensionValueSize : 0) +
		           payloadLength + size_t{ payloadPadding });

        return new RtpPacket(header, headerExtension, payload, payloadLength, payloadPadding, len);
        // Fill in the packet's header and other fields based on the data.
    }

	RtpPacket::RtpPacket(Header *header, 
			HeaderExtension *headerExtension, 
			const uint8_t *payload, 
			size_t payloadLength, 
			uint8_t payloadPadding, 
			size_t size)
		: header(header), headerExtension(headerExtension), payload(const_cast<uint8_t*>(payload)), 
		  payloadLength(payloadLength), payloadPadding(payloadPadding), size(size) {
		
			if (this->header->csrcCount != 0u) {
				this->csrcList = reinterpret_cast<uint8_t *>(header) + HeaderSize;
			}

			
	}




} // namespace Rtp